package com.zx._09_架构.load_balance;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import lombok.Data;

public class LB4_平滑加权轮询算法 {

    /**
     * 【常规可用】非常好用的加权轮询算法。
     * 优点：1. 使用的内存非常少，几个值即可。2.负载均衡出现的效果稳定可靠
     * 缺点：CPU使用率多了点。
     *
     * 比如下面是3个服务以及权重
     * A weightA = 5
     * B weightB = 1
     * C weightC = 2
     *
     * 初始化参数
     * 1. 权重总和：int sumWeight = weightA + weightB + weightC = 8
     * 2. 初始化负载均衡计数器： init = 0,0,0    三个0分别表示 A,B,C 三个负载的初始化值
     * 初始化值加各自的权重   最大的权重   服务   最大的权重-sumWeight
     * 5,1,2               5         A      -3,1,2
     * 2,2,4               4         C      2,2,-4
     * 7,3,-2              7         A      -1,3,-2
     * 4,4,0               4         A      -4,4,0
     * 1,5,2               5         B      1,-3,2
     * 6,-2,4              6         A      -2,-2,4
     * 3,-1,6              6         C      3,-1,-2
     * 8,0,0               8         A      0,0,0  => 开始新的循环
     *
     * @param args
     */
    public static void main(String[] args) {
        Map<String, Integer> weightServer = LB0_common.getWeightServer();

        int sumWeight = weightServer.values().stream().collect(Collectors.summingInt(x -> x));

        List<WeightServer> data = toObject(weightServer);

        for (int i = 0; i < 10; i++) {
            // 自增权重
            selfAddWeight(data);

            // 获得最大权重的server
            WeightServer max = getMax(data);
            LB0_common.saveResult(max.getServer());
            System.out.println(max.getServer());

            // 减去总权重
            max.setWeightDoing(max.getWeightDoing() - sumWeight);
        }

        LB0_common.printResultAndClear();
    }

    private static void selfAddWeight(List<WeightServer> data) {
        for (WeightServer server : data) {
            server.setWeightDoing(server.getWeightDoing() + server.getWeight());
        }
    }

    private static WeightServer getMax(List<WeightServer> data) {
        return data.stream().max((o1, o2) -> o1.getWeightDoing().compareTo(o2.getWeightDoing())).get();
    }

    private static List<WeightServer> toObject(Map<String, Integer> weightServer) {
        List<WeightServer> resList = new ArrayList<>();
        for (Entry<String, Integer> entry : weightServer.entrySet()) {
            WeightServer data = new WeightServer();
            data.setServer(entry.getKey());
            data.setWeight(entry.getValue());
            data.setWeightDoing(0);
            resList.add(data);
        }
        return resList;
    }

    @Data
    private static class WeightServer {

        private String server;
        private Integer weight;
        private Integer weightDoing;
    }
}
